package com.zhaofujun.filequeue;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.MappedByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public abstract class BaseFileMapper {
    protected final String baseDir;
    protected int segmentSize;
    protected final Method unMapMethod;

    public BaseFileMapper(String baseDir, int segmentSize) throws IOException {
        this.baseDir = baseDir;
        this.segmentSize = segmentSize;

        Files.createDirectories(Paths.get(baseDir));

        try {
            Class<?> fileChannelImplClass = Class.forName("sun.nio.ch.FileChannelImpl");
            this.unMapMethod = fileChannelImplClass.getDeclaredMethod("unmap", MappedByteBuffer.class);
            this.unMapMethod.setAccessible(true);
        } catch (Exception e) {
            throw new RuntimeException("初始化 unmap 方法失败", e);
        }
    }


    protected void release(MappedByteBuffer mappedByteBuffer) {
        if (mappedByteBuffer != null) {
            try {
                this.unMapMethod.invoke(null, mappedByteBuffer);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
    }

    // 计算片段文件
    protected SegmentInfo calculateSegmentInfo(long position) {
        long segNumber = position / segmentSize;
        int index = (int) (position % segmentSize);

        Path segmentFile = getSegmentFile(segNumber);
        return new SegmentInfo(position, index, segNumber, segmentFile.toFile());
    }

    protected Path getSegmentFile(long segNumber) {
        return Paths.get(baseDir, "segment_" + segNumber + ".txt");
    }

    public abstract void release() throws InvocationTargetException, IllegalAccessException;

    public int getSegmentSize() {
        return segmentSize;
    }

    public long calculateFirstOffset() {
        return (long) HeadInfo.SIZE * segmentSize;
    }


    public void deleteAllFiles() {
        //删除目录下的所有文件
        try {
            Files.list(Paths.get(baseDir)).forEach(path -> {
                try {
                    Files.delete(path);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //删除目录
        try {
            Files.delete(Paths.get(baseDir));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}
